package run;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import facade.ProcessAssembly;
import javaclass.MyClassLoader;
import process.Process;
import util.DBUtils;
import util.FileUtils;
import util.PathUitls;
import util.PropertyUtils;
import util.StringUilts;

public class ReverseEntity {
	

    private static String packageOutPath;// 包路径
    private static String authorName;// 作者名称
    private static String tablename;// 表名称
    private static String databasename;// 数据库名称
    private List<String> tablenames;// 数据库表名称
    private List<String> colnames; // 列名列表
    private List<String> colTypes; // 列表类型
    private List<String> colAnnotations;// 列注释
    
    public static final String ENTER = "\n";

    
    
    private boolean f_util = false; // java.util.*
    private boolean f_sql = false; // java.sql.*
    
	public static String  path = "";   
	private static String jdbcPropertiesPath = "";

    static{

    	 path = PathUitls.getFilePathOfResource("all.properties");
        jdbcPropertiesPath = PathUitls.getClasspath()+ PropertyUtils.getPro(path, "jdbc.url");
    	 databasename = PropertyUtils.getPro(jdbcPropertiesPath, "databasename");
    	 packageOutPath = PropertyUtils.getPro(jdbcPropertiesPath, "packageOutPath");
    	 tablename =  PropertyUtils.getPro(jdbcPropertiesPath, "tablename");
    	 authorName = PropertyUtils.getPro(jdbcPropertiesPath, "authorName");
    }
    	 
    	 
 
    
    private void genEntity(List<String> tablenames, Connection conn) {
        for (String tablename : tablenames) {
            this.genEntity(tablename, conn);
        }
    }

    private void genEntity(String tablename, Connection conn) {
        String sql = "select * from " + tablename;
        
        DatabaseMetaData dbmd = null;  
        String tableCaption = null;
        try {
	         dbmd = conn.getMetaData();
	         ResultSet resultSet = dbmd.getTables(null, "%", tablename, new String[] { "TABLE" });  
	        
	         while (resultSet.next()) {  
	        	 
	        	 String table=resultSet.getString("TABLE_NAME");
	        	 tableCaption = resultSet.getString("REMARKS");
	        	 if(tableCaption!=null){
	        		 try {
						tableCaption = new String(tableCaption.getBytes(),"UTF-8");
					} catch (UnsupportedEncodingException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	        	 }
	        	
                 System.out.println(table);
                 System.out.println("this is tableCaption:"+tableCaption);
                 
                 if(table.equals(tablename))
                 {
                	 ResultSet rs = conn.getMetaData().getColumns(null,  conn.getMetaData().getUserName(), tablename, "%");  
                	 if(rs!=null)
                	 {
                		 colnames = new ArrayList<String>();
         	            
                		 colTypes = new ArrayList<String>();
         	            
                		 colAnnotations = new ArrayList<String>();
                		 
                		 while(rs.next())
                		 {  
                			 colnames.add(rs.getString("COLUMN_NAME"));
                			 colTypes.add(rs.getString("TYPE_NAME"));
                			 if(null!=rs.getString("REMARKS")){
                				 colAnnotations.add(rs.getString("REMARKS"));
                			 }else{
                				 colAnnotations.add(rs.getString(" "));
                			 }
                		 }
                	 }
                	 
                 }
	        	 
	         }
           
            if (colTypes.contains("DATETIME")) {
                f_util = true;
            }
            if (colTypes.contains("IMAGE")
                    || colTypes.contains("TEXT")) {
                f_sql = true;
            }
            System.out.println(colnames);
            System.out.println(colTypes);
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } finally {
        }
        
        // 写入内存
        String entityContent = parse(tablename);
        String voContent = parseVo(tablename);

        try {
           // File directory = new File("");
           // String outputPath = directory.getAbsolutePath() + "/src/"
                   // + this.packageOutPath.replace(".",File.separator) + StringUtil.initCapAndUnderline(tablename) +File.separator;
            
            String entityOutputPath = PathUitls.getClasspath()
                    /*+ this.packageOutPath.replace(".",File.separator) +File.separator*/
                    +  StringUilts.getFisrtLowerCaseChar(StringUilts.initUnderline(tablename))+File.separator;
            
            
            File entityPath = new File(entityOutputPath);
            
            if(!FileUtils.checkDir(entityPath)){
            	entityPath.mkdirs();
            }
            // java 和 vo
            String entityOutputPathJava = entityOutputPath+ StringUilts.initCapAndUnderline(tablename) + ".java";
            String voOutputPathJava = entityOutputPath+ StringUilts.initCapAndUnderline(tablename) + "Vo.java";
            File entityFile = new File(entityOutputPathJava);
            File voFile = new File(voOutputPathJava);

            if (!entityFile.exists()) {
            	entityFile.createNewFile();
            }
            if (!voFile.exists()) {
            	voFile.createNewFile();
            }
            
            FileWriter fw = new FileWriter(entityFile);
            PrintWriter pw = new PrintWriter(fw);
            
            FileWriter vofw = new FileWriter(voFile);
            PrintWriter vopw = new PrintWriter(vofw);

         
            pw.println(entityContent);
            pw.flush();
            if(pw!=null){
            	pw.close();
            }
            vopw.println(voContent);
            vopw.flush();
            if(vopw!=null){
            	vopw.close();
            }
            
            //编译
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null, null);
            Iterable fileObject = fileManager.getJavaFileObjects(entityOutputPathJava);
            JavaCompiler.CompilationTask task = compiler.getTask(
                    null, fileManager, null, null, null, fileObject);
            task.call();
            fileManager.close();
            
            //生成实例
            MyClassLoader myClassLoader = new MyClassLoader(entityOutputPath);
            //URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL("file:" +  PathUitl.getClasspath()+ this.packageOutPath.replace(".",File.separator) +File.separator+ initCapAndUnderline(tablename) +File.separator)});
            Class beanClass = myClassLoader.loadClass(packageOutPath+".bean."+ StringUilts.initCapAndUnderline(tablename));
            Object obj = beanClass.newInstance();
            
            
          /*  SimpleJavaFileObject fileObject = new JavaSourceFromString(initCapAndUnderline(tablename),entityContent);
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            JavaFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, Arrays.asList(fileObject));
            task.call();
            
            //ClassLoader
            ClassLoader classLoader = fileManager.getClassLoader(null);
            Class beanClass = classLoader.loadClass(initCapAndUnderline(tablename));*/
            
            //dao,Service,vo
           /* Process.processDao(this.packageOutPath,StringUtil.initCapAndUnderline(tablename),entityOutputPath+"dao"+File.separator);
            Process.processService(this.packageOutPath,StringUtil.initCapAndUnderline(tablename),entityOutputPath+"service"+File.separator);
            Process.processMService(this.packageOutPath,StringUtil.initCapAndUnderline(tablename), entityOutputPath+"api"+File.separator, obj);
            Process.processServiceImpl(this.packageOutPath,StringUtil.initCapAndUnderline(tablename),entityOutputPath+"service"+File.separator);
            Process.processController(this.packageOutPath,StringUtil.initCapAndUnderline(tablename),entityOutputPath+"controller"+File.separator);
            Process.processMController(this.packageOutPath,StringUtil.initCapAndUnderline(tablename),entityOutputPath+"api"+File.separator);*/
            ProcessAssembly processAssembly = new ProcessAssembly();
            processAssembly.processAll(packageOutPath, StringUilts.initCapAndUnderline(tablename), entityOutputPath, obj);
  
            //jsp
            Process.processJsp(obj,entityOutputPath,tableCaption);
            beanClass=null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *  生成javaVo文件
     * @param tablename
     * @return
     */
    private String parseVo(String tablename2) {
    	 StringBuffer sb = new StringBuffer();
         sb.append("package " + packageOutPath + ".vo;\r\n");
         if (f_util) {
             sb.append("import java.util.Date;\r\n");
         }
         if (f_sql) {
             sb.append("import java.sql.*;\r\n");
         }
         sb.append("import annotation.*;\r\n");
        
         sb.append("\r\n");
         sb.append("   /**\r\n");
         sb.append("    * " + tablename + " VO\r\n");
         sb.append("    * " + new Date() + " " + authorName + "\r\n");
         sb.append("    */ \r\n");
         sb.append("\r\n\r\npublic class " + StringUilts.initCapAndUnderline(tablename) + "Vo {\r\n");
         sb.append(ENTER);
         processAllAttrsWithOutAnno(sb);// 属性
         processAllMethod(sb);// get set方法
         sb.append("}\r\n");

         
         return sb.toString();
	}

    /**
     * 将所有表名加入tablenames列表
     * @param conn
     * @param tablenames
     */
	private void getAllEntityTable(Connection conn, List<String> tablenames) {
        ResultSet rs = null;
        try {
            DatabaseMetaData dmd = (DatabaseMetaData) conn.getMetaData();
            /*
             * TABLE_CAT String => 
             * TABLE_SCHEM String => 
             * TABLE_NAME String => 
             * TABLE_TYPE String => 
             */
            rs = dmd.getTables(null, null, "%", null);
            while (rs.next()) {
                tablenames.add(rs.getString("TABLE_NAME"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *  生成javaBeam文件
     * @param tablename
     * @return
     */
    private String parse(String tablename) {
        StringBuffer sb = new StringBuffer();
        sb.append("package " + packageOutPath + ".bean;\r\n");
        System.out.println("f_util:"+f_util);
        if (f_util) {
            sb.append("import java.util.Date;\r\n");
        }
        if (f_sql) {
            sb.append("import java.sql.*;\r\n");
        }
        sb.append("import annotation.*;\r\n");
        sb.append("import javax.persistence.Column;\r\n");
        sb.append("import javax.persistence.Entity;\r\n");
        sb.append("import javax.persistence.GeneratedValue;\r\n");
        sb.append("import javax.persistence.Id;\r\n");
        sb.append("import javax.persistence.Table;\r\n");
       
        sb.append("\r\n");
        // class开头
        sb.append("   /**\r\n");
        sb.append("    * " + tablename + " \r\n");
        sb.append("    * " + new Date() + " " + authorName + "\r\n");
        sb.append("    */ \r\n");
        
        sb.append("\r\n@Table(name = \""+tablename+"\")\n");
        sb.append("@Entity\n");
        sb.append("public class " + StringUilts.initCapAndUnderline(tablename) + "{\r\n");
        sb.append(ENTER);
        processAllAttrs(sb);//属性
        processAllMethod(sb);// get set方法
        sb.append("}\r\n");

        
        return sb.toString();
    }

    /**
     * 生成所有属性
     * @param sb
     */
    private void processAllAttrs(StringBuffer sb) {

        for (int i = 0; i < colnames.size(); i++) {
        	if(StringUilts.isNotBlank(colAnnotations.get(i))){
        		
        		sb.append("\t@Caption(\""+ colAnnotations.get(i)+"\")\n");
        	}
        	if("seq_id".equals(colnames.get(i))){
    			sb.append("\t@Id\n");
    			sb.append("\t@GeneratedValue\n");
    			sb.append("\t@Column(name = \""+colnames.get(i)+"\",unique=true,nullable=false)\n");
    		}else{
    			sb.append("\t@Column(name = \""+colnames.get(i)+"\")\n");
    		}
            sb.append("\tprivate " + sqlType2JavaType(colTypes.get(i)) + " "
                    + StringUilts.initUnderline(colnames.get(i)) + ";\r\n");
            sb.append("\n");
        }
        sb.append("\n");

    }
    
    /**
     * 生成所有方法没有注解
     * 
     * @param sb
     */
    private void processAllAttrsWithOutAnno(StringBuffer sb) {

        for (int i = 0; i < colnames.size(); i++) {
        	if(null!= colAnnotations.get(i)&&!colAnnotations.get(i).equals("")){
        		
        		sb.append("\t@Caption(\""+ colAnnotations.get(i)+"\")\n");
        	}
            sb.append("\tprivate " + sqlType2JavaType(colTypes.get(i)) + " "
                    + StringUilts.initUnderline(colnames.get(i)) + ";\r\n");
            sb.append("\n");
        }
        sb.append("\n");

    }

    /**
     * 生成所有方法
     * 字符串生成
     * 
     * @param sb
     */
    private void processAllMethod(StringBuffer sb) {

        for (int i = 0; i < colnames.size(); i++) {
            sb.append("\tpublic void set" + StringUilts.initCapAndUnderline(colnames.get(i)) + "("
                    + sqlType2JavaType(colTypes.get(i)) + " " + StringUilts.initUnderline(colnames.get(i))
                    + "){\r\n");
            sb.append("\t\tthis." + StringUilts.initUnderline(colnames.get(i)) + "=" + StringUilts.initUnderline(colnames.get(i))
                    + ";\r\n");
            sb.append("\t}\r\n");
            sb.append("\tpublic " + sqlType2JavaType(colTypes.get(i)) + " get"
                    + StringUilts.initCapAndUnderline(colnames.get(i)) + "(){\r\n");
            sb.append("\t\treturn " + StringUilts.initUnderline(colnames.get(i)) + ";\r\n");
            sb.append("\t}\r\n");
        }

    }

   
    
    

    /**
     * 转换类型
     * TODO 应该做MAP优化
     * @param sqlType
     * @return
     */
    private String sqlType2JavaType(String sqlType) {

        if (sqlType.equalsIgnoreCase("bit")) {
            return "Boolean";
        } else if (sqlType.equalsIgnoreCase("tinyint")) {
            return "Byte";
        } else if (sqlType.equalsIgnoreCase("smallint")) {
            return "Short";
        } else if (sqlType.equalsIgnoreCase("int")) {
            return "Integer";
        } else if (sqlType.equalsIgnoreCase("bigint")) {
            return "Long";
        } else if (sqlType.equalsIgnoreCase("float")) {
            return "Float";
        } else if (sqlType.equalsIgnoreCase("double")) {
            return "Double";
        }else if (sqlType.equalsIgnoreCase("decimal")
                || sqlType.equalsIgnoreCase("numeric")
                || sqlType.equalsIgnoreCase("real")
                || sqlType.equalsIgnoreCase("money")
                || sqlType.equalsIgnoreCase("smallmoney")) {
            return "Double";
        } else if (sqlType.equalsIgnoreCase("varchar")
                || sqlType.equalsIgnoreCase("char")
                || sqlType.equalsIgnoreCase("nvarchar")
                || sqlType.equalsIgnoreCase("nchar")
                || sqlType.equalsIgnoreCase("text")) {
            return "String";
        } else if (sqlType.equalsIgnoreCase("datetime")) {
        	f_util = true;
            return "Date";
        } else if (sqlType.equalsIgnoreCase("image")||
        		sqlType.equalsIgnoreCase("blob")||sqlType.equalsIgnoreCase("binary")||sqlType.equalsIgnoreCase("mediumblob")) {
            return "byte[]";
        }

        return null;
    }

   

    //启动
    void start() {
        Connection conn = null;
		try {
            conn = DBUtils.getConn();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}

        if ((databasename != null && !databasename.equals(""))
                && (tablename != null && !tablename.equals(""))) {
        	System.out.println("=============同时出现databasename，tablename两个配置===========");
        	System.out.println("=============同时出现databasename，tablename以tablenames生成===========");
        	String[] tablenames = tablename.split(",");
        	for (int i = 0; i < tablenames.length; i++) {
        		genEntity(tablenames[i], conn);
			}
        } else {
            if (databasename != null && !databasename.equals("")) {
                tablenames = new ArrayList<String>();
                getAllEntityTable(conn, tablenames);
                genEntity(tablenames, conn);
            } else {
            	String[] tablenames = tablename.split(",");
            	for (int i = 0; i < tablenames.length; i++) {
            		genEntity(tablenames[i], conn);
				}
            }

            if (conn != null) {
                DBUtils.close(conn);
            }
        }

    }
}
